<?php
class Console {
	
	private $client_cert;
	private $ca_cert;
	private $client_key_pass;
	
	private $host;
	private $port;
	
	private $fp;
	private $errno;
	private $errstr;
	
	private $buff = '';
	
	public function Console ($cert, $cacert) {
		$this->client_cert = $cert;
		$this->ca_cert = $cacert;
	}
	
	public function setKeyPassphrase($passphrase) {
		$this->client_key_pass = $passphrase;
	}
	
	public function connect($host, $port) {
		$opts = array('ssl' => array(
			'verify_peer' => true,
			'local_cert'=> $this->client_cert,
			'cafile' => $this->ca_cert,
			'allow_self_signed' => true,
			'verify_depth' => 2
		));
		if ($this->client_key_pass)
			$opts['ssl']['passphrase'] = $this->client_key_pass;
		$context = stream_context_create($opts);
		$this->fp = stream_socket_client('tls://'.$host.':'.$port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
		if (!$this->fp) {
			$this->errno = $errno;
			$this->errstr = $errstr;
			return false;
		}
		$this->host = $host;
		$this->port = $port;
		return true;
	}
	
	public function read($remove_stars = false) {
		if ($this->buff == '') {
			$this->buff = fread($this->fp, 2048);
			$this->adjustBuffer();
		}
		$pos = strpos($this->buff, chr(0));
		if ($pos === false)
			return false;
		if ($remove_stars && substr($this->buff, 0, 3) == ' * ')
			$this->buff = substr($this->buff, 3);
		$string = substr($this->buff, 0, $pos);
		$this->buff = substr($this->buff, $pos + 1);
		return $string;
	}
	
	public function write($cmd) {
		fwrite($this->fp, $cmd);
	}
	
	public function transaction($cmd, $remove_stars = false) {
		$state = 0;
		$buff = '';
		
		$this->write('transaction '.$cmd);
		do {
			$string = $this->read($remove_stars);
			switch ($state) {
				case 0:
					if ($string == 'transaction begin')
						$state = 1;
					break;
				case 1:
					if ($string != 'transaction end')
						$buff .= ($buff == '' ? $string : "\n".$string);
						break;
			}
		} while ($string != 'transaction end');
		return $buff;
	}
	
	public function getErrNo() {
		return $this->errno;
	}
	
	public function getErrStr() {
		return $this->errstr;
	}
	
	public function getFullError() {
		return '['.$this->errno.'] '.$this->errstr;
	}
	
	public function getVariables() {
		$variables = array();
		$vars = $this->transaction('variables list');
		$vars = explode("\n", $vars);
		foreach ($vars as $var) {
			$value = strstr($var, ' = ');
			$name = substr($var, 0, strlen($var) - strlen($value));
			$variables[$name] = substr($value, 3);
		}
		return $variables;
	}
	
	public function getVariable($name) {
		return $this->transaction('variables get '.$name);
	}
	
	public function setVariable($name, $value = '') {
		$this->write('variables set '.$name.' '.$value);
	}
	
	public function getLoadedModules() {
		$mods = $this->transaction('modules list');
		$mods = explode("\n", $mods);
		return $mods;
	}
	
	public function shutdown() {
		$this->write('shutdown');
	}
	
	private function adjustBuffer() {
		$this->buff = str_replace("\n", chr(0), $this->buff);
		$this->buff = str_replace("\r", chr(0), $this->buff);
	}
	
}